


// 第二次

// var value = 1
// function foo (v) {
//   v = 2
//   console.log(v)
// }
// foo(value)
// console.log(value)


// var obj = {
//   value: 1,
// }
// function foo (o) {
//   o.value = 2
//   console.log(o.value)
// }
// foo(obj)
// console.log(obj.value)


// var foo = {
//   value: 1
// }
// function bar () {
//   console.log(this.value)
// }
// bar.call(foo)

// 1. call -> this foo params
// 2. bar 执行

// let foo = {
//   value: 1,
//   bar: function () {
//     console.log(this.value)
//   }
// }
// foo.bar()

// delete foo.bar

// foo.fn = bar
// foo.fn()
// delete foo.fn

// bar.call(foo)

// 手写call
// Function.prototype.call2 = function (context) {
//   // console.log(context)
//   // console.log(this)
//   // context -> foo
//   // this -> bar
//   context.fn = this
//   context.fn()
//   delete context.fn
// }

// var foo = {
//   value: 1
// }
// function bar () {
//   // console.log(this)
//   console.log(this.value)
// }
// bar.call2(foo)

// var foo = {
//   value: 1
// }

// function bar (name, age) {
//   console.log(name, age, this.value)
// }

// bar.call(foo, 'chenghuai', 18)
// bar.call2(foo, 'chenghuai', 18)


// 加入参数
// Function.prototype.call2 = function (context) {
//   // context -> foo
//   // this -> bar
//   // console.log(arguments)
//   context.fn = this
//   context.fn = bar
//   let args = [...arguments].slice(1)
//   // foo.fn('chenghuai', 18)
//   // bar('chenghuai', 18)
//   delete context.fn
// }

// var foo = {
//   value: 1
// }

// function bar (name, age) {
//   console.log(name, age, this.value)
// }

// // bar.call(foo, 'chenghuai', 18)
// bar.call2(foo, 'chenghuai', 18)



// var value = 1
// function bar () {
//   console.log(this.value)
// }

// bar.call(null)

// var obj = {
//   value: 1
// }
// function bar (name, age) {
//   return {
//     value: this.value,
//     name,
//     age
//   }
// }

// console.log(bar.call(obj, 'chenghuai', 18))

// 加入指定为window
// Function.prototype.call2 = function (context) {
//   var context = context || window
//   let fnSymbol = Symbol()
//   context.fnSymbol = this

//   let args = [...arguments].slice(1)
//   let result = context.fnSymbol(...args)
//   delete context.fnSymbol

//   return result
// }

// var value = 1
// function bar () {
//   console.log(this.value)
// }

// bar.call2(null)

// var obj = {
//   value: 1
// }
// function bar (name, age) {
//   return {
//     value: this.value,
//     name,
//     age
//   }
// }

// console.log(bar.call2(obj, 'chenghuai', 18))


// ES6版本
// Function.prototype.call2 = function (context, ...args) {
//   if (typeof context === 'undefined' || typeof context === 'null') {
//     context = window
//   }

//   let fnSymbol = Symbol()
//   context.fnSymbol = this
//   let result = context.fnSymbol(...args)
//   delete context[fnSymbol]

//   return result
// }

// call apply 区别
// Function.prototype.apply2 = function (context, args) {
//   var context = context || window
//   let fnSymbol = Symbol()
//   context.fnSymbol = this

//   let result = context.fnSymbol(...args)
//   delete context.fnSymbol

//   return result
// }

// bind
// var foo = {
//   value: 1
// }

// function bar () {
//   console.log(this.value)
// }

// var bindFoo = bar.bind(foo)

// bindFoo()

// Function.prototype.bind2 = function (context) {
//   // context === foo
//   // bar === this

//   var _this = this  // 记录bar
//   return function () {
//     return _this.apply(context)
//   }
// }



// 传参版本
// Function.prototype.bind2 = function (context, ...args) { // args = ['chenghuai']
//   // bind2的入参传递的
//   // context === foo
//   // bar === this

//   var _this = this  // 记录bar
//   return function (...returnArgs) {  // returnArgs = [18]
//     // 18 这个函数的入参传递
//     // ['chenghuai', 18]
//     return _this.apply(context, [...args, ...returnArgs])  // this === window  _this === bar
//   }
// }
// var foo = {
//   value: 1
// }

// function bar (name, age) {
//   console.log(name, age, this.value)
// }

// var bindFoo = bar.bind(foo, 'chenghuai')
// bindFoo(18)

// bind 作为构造函数使用
// var value = 2
// var foo = {
//   value: 1
// }
// function bar (name, age) {
//   this.habit = 'shopping'
//   console.log(name, age, this.value)
// }
// bar.prototype.friend = 'dzq'
// var bindFoo = bar.bind(foo, 'chenghuai')
// var obj = new bindFoo(18)  // bind作为构造函数使用，this会指向实例  this -> obj  否则 this -> context
// console.log(obj)

// Function.prototype.bind2 = function (context, ...args) {
//   var _this = this
//   return function (...returnArgs) {
//     return _this.apply(context, [...args, ...returnArgs])
//   }
// }

// arguments对象
// 第一版
Function.prototype.call2 = function (context) {
  console.log(context)

  // 首先要获取调用call的函数，用this可以获取
  context.fn = this
  context.fn()
  delete context.fn
}

// 测试一下
let foo = {
  value: 1
}

function bar () {
  console.log(this.value)
}

bar.call2(foo) // 1